package common.rng;

import java.util.Random;

/**
 * 
 * WELL1024 RNG
 * 
 *  - adapted from Java SSJ library code by Pierre L'Ecuyer et al 
 *      http://www.iro.umontreal.ca/~simardr/ssj/indexe.html
 *    and C version by Panneton et al
 *      http://www.iro.umontreal.ca/~panneton/well/WELL1024a.c
 */
public class WELL1024  {
   
   private static final double NORM = 2.32830643653869628906e-10;

   private static final int MASK = 0x0000001F;

//   private static final int W = 32;
   private static final int R = 32;
   private static final int M1 = 3;
   private static final int M2 = 24;
   private static final int M3 = 10;

   private int state_i = 0;
   private int[] state;

 
   public WELL1024(int init[]) 
   {
      state = new int[R];
      for(int j = 0; j < R; j++) {
         state[j] = init[j];
      }
      state_i = 0;
   }

   private static int[] randVect() 
   {
	   int[] init = new int[R];
	   Random r = new Random();
	   for (int i = 0; i < R; i++) init[i] = r.nextInt();
	   return init;
   }

   private static int[] randVect(long seed) 
   {
	   int[] init = new int[R];
	   Random r = new Random(seed);
	   for (int i = 0; i < R; i++) init[i] = r.nextInt();
	   return init;
   }
   
   public WELL1024()
   {
	   this(randVect());
   }

   public WELL1024(long seed)
   {
	   this(randVect(seed));
   }
      
   public double nextValue() {
      int z0, z1, z2;

      z0    = state[(state_i + 31) & MASK];
      z1    = state[state_i] ^ (state[(state_i + M1) & MASK] ^
                                (state[(state_i + M1) & MASK] >>> 8));
      z2    = (state[(state_i + M2) & MASK] ^
               (state[(state_i + M2) & MASK] << 19)) ^
              (state[(state_i + M3) & MASK] ^
               (state[(state_i + M3) & MASK] << 14));
      state[state_i] = z1 ^ z2;
      state[(state_i + 31) & MASK] = (z0 ^ (z0 << 11)) ^
                                     (z1 ^ (z1 << 7)) ^ (z2 ^ (z2 << 13));
      state_i = (state_i + 31) & MASK;

      long result = state[state_i];

      return ((double) (result > 0 ? result : result + 0x100000000L) * NORM);
   }
 
   public static void main(String[] args) {
	   WELL1024 w = new WELL1024();
	   double s = 0;
	   for (int i = 0; i < 1000000; i++)
		   s += w.nextValue();
	   System.out.println(s/1000000);
	   
	   for (int i = 0; i < 1000; i++) {
		   System.out.println(w.nextValue() + " " + w.nextValue() + ";");
	   }
   }
}